Skip to content

Fix new namespace creation placing files under absolute filesystem path#83

Merged
ericdallo merged 4 commits into
clojure-lsp:masterfrom
madgodinc:fix/new-file-namespace-path
Apr 26, 2026
Merged

Fix new namespace creation placing files under absolute filesystem path#83
ericdallo merged 4 commits into
clojure-lsp:masterfrom
madgodinc:fix/new-file-namespace-path

Conversation

@madgodinc

Copy link
Copy Markdown
Contributor

Bug

Creating a new Clojure namespace via Project view → New → Clojure namespace
sometimes creates the file under an absolute host path inside the target
directory.

Example: clicking "New namespace" on src/project_name/ and entering
test creates the file at:

src/project_name/home/username/code/clojure_proj/project_name/src/test.clj

instead of the expected:

src/project_name/test.clj

Root cause

create-file-from-template in new_file.clj built an absolute canonical
path via io/file + getCanonicalPath and then tried to strip the
directory prefix with string/replace-first.

This is fragile:

  • clojure-lsp may return source-paths as file:// URIs
  • VirtualFile.getPath may use a different separator than getCanonicalPath
  • source-paths may be project-relative strings

When the prefix does not match, replace-first silently returns the full
absolute path, which IntelliJ then interprets as a path relative to the
target directory and recreates the whole host path tree inside it.

dir->partial-namespace had the same class of bug — if the prefix didn't
match it returned (subs filename 1) which produced nonsense namespaces
like home.username.code.proj....

Fix

Rewrite path math using java.nio.file.Path:

  • Normalize URIs (file://) and separators via a helper ->path
  • Use Path.startsWith for source-path detection (real segment-wise
    comparison instead of substring matching)
  • Use Path.relativize to compute
    • the directory's path relative to the source root (for the default
      namespace prefix in the dialog), and
    • the namespace path relative to the directory (for the new-name
      passed to CreateFileFromTemplateAction/createFileFromTemplate)

No more string-prefix matching on raw paths.

Testing

Didn't rebuild locally (no toolchain on the machine I made the fix on).
Relying on CI + reviewer verification. Happy to iterate on review.

When creating a new Clojure namespace from Project view, the new file
could be created under a path that contains the absolute host path
segments, e.g. creating src/proj/test.clj ended up at
src/proj/home/user/code/proj/src/test.clj.

Root cause: create-file-from-template built an absolute canonical path
via io/file + getCanonicalPath and then tried to strip the directory
prefix with string/replace-first. This is fragile: clojure-lsp may
return source-paths as file:// URIs or with different separators than
VirtualFile.getPath, causing the prefix strip to silently fail and
leave the full absolute path as the new file name. IntelliJ then
interprets it as a path relative to the target directory and recreates
the whole host path tree inside it.

Fix: rewrite path math using java.nio.file.Path. source-path detection
normalizes URIs and separators, then relativize is used to compute the
directory's path relative to the source root and the namespace path
relative to the directory. No more string-prefix matching.

Also cleans up dir->partial-namespace which used to silently produce
garbage (home.user.code.proj...) when the source-path prefix did not
match.
@madgodinc

Copy link
Copy Markdown
Contributor Author

This failing test (slurp-action-test for ClojureLSP.ForwardSlurp) appears unrelated to this change — the PR only modifies new_file.clj
(namespace creation from Project view). The failure happens during IntelliJ test fixture instantiation (UnsupportedOperationException wrapped in
InvocationTargetException), which looks like a headless IDE test framework issue rather than a regression from this patch.

The "Publish Test Report" step also failed with Resource not accessible by integration, which is a known limitation for PRs from forks (the
GITHUB_TOKEN gets read-only permissions, so mikepenz/action-junit-report cannot create check runs). Not related to the patch either.

Could a maintainer re-run the failed job or confirm whether slurp-action-test is currently flaky on master? Happy to rebase or iterate if anything
needs adjusting.

(str ".")))))))

(defn ^:private ns->rel-path
"Возвращает путь нового файла ОТНОСИТЕЛЬНО dir, как требует createFileFromTemplate."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's please use english

@ericdallo

Copy link
Copy Markdown
Member

Could you add a CHANGELOG entry under ## [Unreleased]? Something like:

- Fix new namespace creation incorrectly creating files under the absolute host filesystem path. #83

@ericdallo

ericdallo commented Apr 25, 2026

Copy link
Copy Markdown
Member

The CI failure (slurp-action-test) is unrelated to this PR — it's a flake in the IntelliJ test framework / LSP4IJ nightly bootstrap. I'll fix it on master soon, no action needed here.

@ericdallo

Copy link
Copy Markdown
Member

The slurp-action-test failure on master is now fixed (303477d). It was caused by two independent breakages introduced by newer LSP4IJ versions:

  1. LSP4IJ added two default methods to LanguageServerFactory that our gen-class-backed ClojureLanguageServerFactory didn't stub.
  2. LSP4IJ's FileSystemWatcherManager calls VirtualFile.toNioPath() on the project base, which throws on the in-memory TempFileSystem used by clj4intellij.test/setup. Bumped clj4intellij to 0.9.0 (which adds setup-heavy) and switched the test fixture to a heavy/disk-backed one.

Could you merge master into this branch and push? CI should go green afterwards. Sorry for the delay!

madgodinc and others added 3 commits April 26, 2026 08:14
The previous docstring was in Russian; translate to match the rest of
the codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ericdallo

Copy link
Copy Markdown
Member

Thank you!

@ericdallo ericdallo merged commit 33ef55b into clojure-lsp:master Apr 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants